#!/usr/bin/python
######
#       modhandler.py
#       Copyright Etelos Inc. 2007
#       Darien Hager
#       darien@etelos.com
######
import time
from filemodule import filemodule, folder, file
from threading import Thread
class modhandler(Thread):
	
	MIN_TS = 315561600 	# Unix timestamp for 1980
	MAX_TS = 1577865600	# Unix timestamp for 2020
				# (The Y2020 bug!)				
	EXP_ADD = "ADD"
	EXP_DEL = "DEL"
	
	SLEEPTIME = 0.2 # secs # Decreased for checking deadlocks
	
	def __init__(self,filemod, coordinator):
		self.__cmod = coordinator
		self.__fmod = filemod
		self.file_flag = False # Check filemodule when true'ed
		self.running = False
		Thread.__init__(self)
		Thread.setDaemon(self,True)
	def start(self):		
		self.running = True
		Thread.start(self)
	def stopThread(self):
		self.__running = False
	def run(self):
		while(self.running):
			if self.file_flag:
				self.file_flag = False
				(added,deleted,modified) = self.__fmod.getEvents(True)			
				for e in added:
					
					pb = tuple([bit.decode('utf-8') for bit in e.getPathbits()])
					ok = self.__checkEvent(pb,self.EXP_ADD)
					if(ok): self.__cmod.notifyAdd(pb)
				for e in deleted:
					pb = tuple([bit.decode('utf-8') for bit in e.getPathbits()])					
					ok = self.__checkEvent(pb,self.EXP_DEL)
					if(ok): self.__cmod.notifyDel(pb)				
				for (e,m) in modified:
					pb = tuple([bit.decode('utf-8') for bit in e.getPathbits()])
					ok = self.__checkEvent(pb,m)
					if(ok): self.__cmod.notifyMod(pb,m)
			# Now trigger the coordinator to examine GUI responses			
			self.__cmod.getGuiAdapter().processResponses()
			# Sleep!
			time.sleep(self.SLEEPTIME)
	def __checkEvent(self,pathbits,status):
		# Check that this is on our subscription list. If it isn't, odds
		# are that it's a temporary file or backup or something.
		has = self.__cmod.isSubbed(pathbits)
		if not has:
			return False # Not subscribed file or DB object
			
		# Fine, then check if we were expecting it...
		expected = self.__cmod.getExpect(pathbits)
		if(expected == False):
			# No expectation at all? That means we don't have any
			# basis to ignore it.
			return True
		if(expected == status):
			self.__cmod.delExpect(pathbits)
			return False
		
		# Test if status is numeric.
		try:
			status = int(status)
			expected = int(expected)
		except ValueError, e:
			# One or the other is not numeric. 
			# Unexpected. But clear & continue
			self.__cmod.delExpect(pathbits)
			return True
			
		# So it's numeric. Now lets' check if it's "reasonable"
								

		if ((status < self.MIN_TS) or (status > self.MAX_TS) ):				
			assert False, "Event detail string is not any reasonable timestamp, off by decades ("+status+")"
			self.__cmod.delExpect(pathbits)
			return False # No way we want to process this, right? It's clearly bogus.
			
		# So it's valid? One final check. Remember our ignore-list checks
		# earlier? Even if the timestamps are not exact, an ignore-timestamp
		# which is newer than the detected change means we ignore the event.
			

		if(status >= expected):
			# Unexpected. Hmm. Ignore this once.
			self.__cmod.delExpect(pathbits)
			return True # ignored
		else:
			# We're ignoring the change, but just once.
			self.__cmod.delExpect(pathbits)
			return False
			
		# Subscribed, but not on ignore list... Of course, continue.
		return True